package com.burgeon.backend.service.Impl;


import com.burgeon.backend.Rest.User.GETUserByOpenid;
import com.burgeon.backend.Rest.User.UserExist;
import com.burgeon.backend.Rest.User.UserReadOpenid;
import com.burgeon.backend.Rest.coupon.util.CreateIntegral;
import com.burgeon.backend.allocation.Config;
import com.burgeon.backend.entity.*;
import com.burgeon.backend.mappers.AccountMapper;
import com.burgeon.backend.mappers.TemplateMapper;
import com.burgeon.backend.mappers.UserMapper;
import com.burgeon.backend.mappers.WechatMapper;
import com.burgeon.backend.service.CodeService;
import com.burgeon.backend.service.CouponService;
import com.burgeon.backend.service.MessageTemplateService;
import com.burgeon.backend.service.WechatService;
import com.burgeon.backend.service.ex.ErrorDataException;
import com.burgeon.backend.service.ex.PhoneException;
import com.burgeon.backend.service.ex.UserNotFoundException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tomcat.util.codec.binary.Base64;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class WechatServiceImpl implements WechatService {
    @Autowired
    private WechatMapper wechatMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AccountMapper accountMapper;
    @Autowired
    private TemplateMapper templateMapper;
    @Autowired
    private CouponService couponService;
    @Autowired
    private MessageTemplateService messageTemplateService;

    private final static Log logger = LogFactory.getLog(WechatService.class);

    @Override
    public String H5Opneid(String code, String token) {
        Wechat data = getInfo(token);
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?" +
                "appid=" + data.getAppid() + "&secret=" + data.getSecret() + "&code=" + code + "&grant_type=authorization_code";
        RestTemplate restTemplate = new RestTemplate();
        String str = restTemplate.getForObject(url, String.class);
        System.err.println(str);

        String openid = null;
        try {
            JSONObject jsonObject = new JSONObject(str);
            openid = jsonObject.getString("openid");

        } catch (JSONException e) {
            e.printStackTrace();
        }

        System.err.println("openid=="+openid);
        return openid;
    }

    @Override
    public void UpDataWechat(Wechat wechat) throws ErrorDataException {

        if (wechatMapper.getWechatByAccount(wechat.getAccount()) == null) {
            Integer row = wechatMapper.addWechat(wechat);
            if (row != 1) {
                throw new ErrorDataException("出现错误");
            }
            return;
        }
        Integer row = wechatMapper.updataWechat(wechat);
        if (row != 1) {
            throw new ErrorDataException("出现错误");
        }
    }

    @Override
    public Wechat GetWechatByAccount(String account) {
        return wechatMapper.getWechatByAccount(account);
    }

    @Override
    public String GetAccesTokenByAccount(String account) {
        String token = accountMapper.GetTokenForAccount(account);
        return GetAccesToken(token);
    }

    @Override
    public Wechat getInfo(String token) throws ErrorDataException {
        Config config = new Config();
        Wechat wechat = getWechat(token);
        if (wechat == null) {
            throw new ErrorDataException("获取数据错误");
        }
        wechat.setResponseType(config.getResponse_type());
        wechat.setScope(config.getScope());
        System.err.println("wechat=="+wechat);
        return wechat;
    }

    @Override
    public void Judge(String code, String token, HttpSession session) throws UserNotFoundException {

        Wechat data = getInfo(token);
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?" +
                "appid=" + data.getAppid() + "&secret=" + data.getSecret() + "&code=" + code + "&grant_type=authorization_code";
        RestTemplate restTemplate = new RestTemplate();
        String str = restTemplate.getForObject(url, String.class);
        System.err.println(str);
        User user = null;

        try {
            JSONObject jsonObject = new JSONObject(str);
            String accessToken = jsonObject.getString("access_token");
            String refreshToken = jsonObject.getString("refresh_token");
            String openid = jsonObject.getString("openid");
            session.setAttribute("openid", openid);
            System.err.println("openid=="+openid);
            //改openid搜索系统会员
            //user = userMapper.FindUser(openid, token);
            Info info = GetInfo(token);
            accessToken = GetAccesToken(token);
            try {
                if (null == userMapper.FindUser(openid, token)) {
                    InsertUser(accessToken, openid, token);
                }
            } catch (Exception e) {

                System.err.println("创建会员错误");
            }
            GETUserByOpenid getUserByOpenid = new GETUserByOpenid(info.getUrl(), info.getAccount(), info.getPassword());

            user = getUserByOpenid.getData(openid);
            session.setAttribute("phone", user.getPhone());
            //getAward(token,user.getPhone(),openid);

            try {
                    user.setToken(token);
                    user.setAccount(token);
                    user.setOpenid(openid);
                    user.setFinish("Y");
                    userMapper.Register(user);
            } catch (Exception e) {
                System.err.println(e.getMessage());
            }

        } catch (Exception e) {
            System.err.println("openid未找到");
            throw new UserNotFoundException();
        }
        if (user == null) {
            throw new UserNotFoundException();
        }

    }

    @Override
    public void JudgeByPhone(String token,String phone, HttpSession session) throws UserNotFoundException {
        String openid = session.getAttribute("openid").toString();
        User user = null;
        String accessToken = GetAccesToken(token);
        try {
            Info info = GetInfo(token);
            try {
                if (null == userMapper.FindUser(openid, token)) {
                    InsertUser(accessToken, openid, token);
                }
            } catch (Exception e) {
                System.err.println("sql创建会员错误");
            }
            //GETUserByOpenid getUserByOpenid = new GETUserByOpenid(info.getUrl(), info.getAccount(), info.getPassword());
            UserExist userExist = new UserExist(info.getUrl(), info.getAccount(), info.getPassword());

            user = userExist.getData(phone);
            System.err.println("user="+user);
            user.setOpenid(openid);
            user.setToken(token);
            user.setAccount(token);
            userMapper.Register(user);//同步数据库数据

            UserReadOpenid userReadOpenid = new UserReadOpenid(info.getUrl(), info.getAccount(), info.getPassword());
            try {
                userReadOpenid.getData(user.getId(), openid);
            } catch (Exception e) {
                logger.error(e.getMessage() + "写入数据错误");
            }

            //session.setAttribute("phone", user.getPhone());
            //getAward(token,user.getPhone(),openid);
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.err.println("卡号未找到未找到");
            throw new UserNotFoundException();
        }
        if (user == null) {
            throw new UserNotFoundException();
        }
    }

    private void getAward(String token,String phone,String openid){
        String account = accountMapper.GetAccountForToken(token);
        Info info = GetInfo(token);
        UserExist userExist = new UserExist(info.getUrl(), info.getAccount(), info.getPassword());
        User user;
        try {
            user = userExist.getData(phone);
        } catch (Exception e) {
            throw new PhoneException();
        }
        //写入openid
        UserReadOpenid userReadOpenid = new UserReadOpenid(info.getUrl(), info.getAccount(), info.getPassword());
        try {
            userReadOpenid.getData(user.getId(), openid);
        } catch (Exception e) {
            logger.error(e.getMessage() + "数据错误");
            throw new ErrorDataException("数据错误");
        }

        user.setToken(token);
        Date now = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String dateString = sdf.format(now);
        user.setCreateTime(dateString);
        user.setPhone(phone);
        user.setOpenid(openid);
        user.setAccount(account);

        userMapper.Register(user);
        User finalUser = user;

        Thread thread = new Thread(() -> {
            logger.error(finalUser);

            //发券  发积分  发消息
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ignored) {
            }
            TemplateSwitch templateSwitch = templateMapper.FindTemplateSwitch(account);
            if ("Y".equals(templateSwitch.getSwitch1())) {
                //发券
                logger.error(templateSwitch);
                couponService.addCoupon(templateSwitch.getValue1(),phone,account);
            }

            if ("Y".equals(templateSwitch.getSwitch2())){
                CreateIntegral createIntegral = new CreateIntegral(info.getUrl(), info.getAccount(), info.getPassword());
                try {
                    Thread.sleep(1000);
                    createIntegral.getData(phone,"-"+templateSwitch.getValue2());
                    messageTemplateService.SendMessageForNewUser(token,openid,phone,templateSwitch.getValue2(),finalUser.getName());
                } catch (Exception e) {
                    logger.error("新会员积分调整错误"+ Arrays.toString(e.getStackTrace())+e.getMessage());
                }
            }
        });
        thread.start();
    }

    @Override
    public String GetAccesToken(String token) {
        Date now = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH");
        String dateString = sdf.format(now);
        AccessToken oldAccessToken = wechatMapper.getAccessToken(token);

        if (null != oldAccessToken && dateString.equals(oldAccessToken.getDate())) {
            return oldAccessToken.getAccessToken();
        }

        String accessToken;
        Wechat wechat = getWechat(token);
        String grantType = "client_credential";
        String appid = wechat.getAppid();
        String secret = wechat.getSecret();
        String url = "https://api.weixin.qq.com/cgi-bin/token?" +
                "grant_type=" + grantType +
                "&appid=" + appid +
                "&secret=" + secret;
        RestTemplate restTemplate = new RestTemplate();

        try {
            String str = restTemplate.getForObject(url, String.class);
            System.err.println("str=="+str);
            accessToken = new JSONObject(str).getString("access_token");
        } catch (JSONException e) {
            System.err.println("获取access_token失败");
            return null;
        }

        AccessToken data = new AccessToken();
        data.setAccessToken(accessToken);
        data.setToken(token);
        data.setAccount(wechat.getAccount());
        data.setDate(dateString);

        Integer row = wechatMapper.upDataAccessToken(data);
        if (row != 1) {
            //为acc添加accesstoken
            wechatMapper.addAccessToken(data);
        }

        return accessToken;
    }

    @Override
    public String GetJsapiTicket(String accessToken, String token) {
        Wechat wechat = getWechat(token);

        Date now = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH");
        String dateString = sdf.format(now);
        JsapiTicket oldJsapiTicket = wechatMapper.getJsapiTicket(token);

        if (null != oldJsapiTicket && dateString.equals(oldJsapiTicket.getDate())) {
            return oldJsapiTicket.getJsapiTicket();
        }

        String jsapiTicket;

        String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?" +
                "access_token=" + accessToken + "&type=jsapi";
        RestTemplate restTemplate = new RestTemplate();
        String str = restTemplate.getForObject(url, String.class);
        System.err.println(str);
        try {
            jsapiTicket = new JSONObject(str).getString("ticket");
        } catch (JSONException e) {
            System.err.println("获取ticket失败");

            return null;
        }

        JsapiTicket data = new JsapiTicket();
        data.setAccount(wechat.getAccount());
        data.setDate(dateString);
        data.setJsapiTicket(jsapiTicket);
        data.setToken(token);

        Integer row = wechatMapper.upDataJsapiTicket(data);
        if (row != 1) {
            wechatMapper.addJsapiTicket(data);
        }

        return jsapiTicket;
    }

    @Override
    public Map GetSDKSign(String url, String token) {
        String accessToken = GetAccesToken(token);
        String ticket = GetJsapiTicket(accessToken, token);
        Map data = sign(ticket, url);

        data.put("debug", "true");
        data.put("appId", getWechat(token).getAppid());

        return data;
    }

    @Override
    public String findAppId(String token) {
        return wechatMapper.findAppId(token);
    }

    private void InsertUser(String accessToken, String OPENID, String token) throws Exception {
        String url = "https://api.weixin.qq.com/cgi-bin/user/info?" +
                "access_token=" + accessToken + "&openid=" + OPENID + "&lang=zh_CN";
        System.err.println(url);
        RestTemplate restTemplate = new RestTemplate();
        String str = restTemplate.getForObject(url, String.class);
        System.err.println("数据=" + str);

        String result = new String(str.getBytes(StandardCharsets.ISO_8859_1), "UTF-8");

        JSONObject jsonObject = new JSONObject(result);
        String openid = jsonObject.getString("openid");
        String nickname = jsonObject.getString("nickname");
        String sex = jsonObject.getString("sex");
        String city = jsonObject.getString("city");
        String province = jsonObject.getString("province");
        String country = jsonObject.getString("country");
        String headimgurl = jsonObject.getString("headimgurl");
        User user = new User();
        user.setImg(headimgurl);
        user.setToken(token);
        //nickname = Base64.encodeBase64String(nickname.getBytes("UTF-8"));
        user.setNickname("--");
        user.setOpenid(openid);
        user.setCity(city);
        user.setProvince(province);
        user.setCountry(country);
        user.setGender(sex.equals("1") ? "男" : "女");

        userMapper.addUser(user);

    }

    private Wechat getWechat(String token) {
        return wechatMapper.getWechat(token);
    }

    private Info GetInfo(String token) {
        return accountMapper.GetTokenData(token);
    }

    public static Map<String, String> sign(String jsapi_ticket, String url) {
        Map<String, String> ret = new HashMap<String, String>();
        String nonce_str = create_nonce_str();
        String timestamp = create_timestamp();
        String string1;
        String signature = "";

        //注意这里参数名必须全部小写，且必须有序
        string1 = "jsapi_ticket=" + jsapi_ticket +
                "&noncestr=" + nonce_str +
                "&timestamp=" + timestamp +
                "&url=" + url;


        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        } catch (NoSuchAlgorithmException e) {
            System.err.println("wechat签名错误NoSuchAlgorithmException");
        } catch (UnsupportedEncodingException e) {
            System.err.println("wechat签名错误UnsupportedEncodingException");
        }

        ret.put("url", url);
        ret.put("jsapi_ticket", jsapi_ticket);
        ret.put("nonceStr", nonce_str);
        ret.put("timestamp", timestamp);
        ret.put("signature", signature);

        return ret;
    }

    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    private static String create_nonce_str() {
        return UUID.randomUUID().toString();
    }


    private static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }


}
